package appml

import (
	"runtime"
	"slices"
	"time"
)

// 进程管理器
type ProcessManager struct {
	processes map[string]*Process
}

// 创建进程管理器
func NewProcessManager() *ProcessManager {
	return &ProcessManager{processes: make(map[string]*Process)}
}

// 获取进程
func (m *ProcessManager) GetProcess(name string) *Process {
	return m.processes[name]
}

// 添加进程
func (m *ProcessManager) SetProcess(proc *Process) error {
	if proc == nil {
		return NewErr(runtime.Caller(0)).Msg("process is nil")
	}
	if old, exists := m.processes[proc.name]; exists {
		if slices.Equal(old.params, proc.params) {
			for pid, proc := range proc.processes {
				if _, exists := old.processes[pid]; !exists {
					old.processes[pid] = proc // 旧进程中不存在，添加
				}
			}
			return nil // 新旧相同，不处理
		}
		if err := m.DelProcess(old.name); err != nil {
			return NewErr(runtime.Caller(0)).Err(err) // 新旧不同，删除旧进程
		}
	}
	m.processes[proc.name] = proc
	return nil
}

// 删除进程：删除前会先 Kill 进程。删除后不再受 ProcessManager 管理
func (m *ProcessManager) DelProcess(name string) error {
	err := m.Kill(name)
	if err == nil {
		delete(m.processes, name)
		return nil
	}
	return NewErr(runtime.Caller(0)).Err(err)
}

// 从已管理的进程中删除不在 names 中的进程
func (m *ProcessManager) DelProcessIfNotIn(names ...string) error {
	return MapDelete(m.processes, func(name string, v *Process) (bool, error) {
		for _, n := range names {
			if name == n {
				return false, nil
			}
		}
		return true, nil
	}, func(procs map[string]*Process, name string) {
		if err := m.DelProcess(name); err == nil {
			delete(procs, name)
		}
	})
}

// 仅 Kill 进程而不删除进程，被 Kill 的进程依然受 ProcessManager 管理
func (m *ProcessManager) Kill(name string) error {
	proc := m.GetProcess(name)
	if proc == nil {
		return nil
	}
	return NewErr(runtime.Caller(0)).If(proc.Kill())
}

// 启动进程
func (m *ProcessManager) Start(name string) error {
	proc := m.GetProcess(name)
	if proc == nil {
		return nil
	}
	return NewErr(runtime.Caller(0)).If(proc.StartIfNotRunning())
}

// 退出进程后重新启动进程
func (m *ProcessManager) Restart(name string) error {
	if err := m.Kill(name); err != nil {
		return err
	}
	time.Sleep(time.Second)
	return m.StartIfNotRunning(name)
}

// 检查指定进程是否已启动，如果未启动则启动它
func (m *ProcessManager) StartIfNotRunning(name string) error {
	proc := m.GetProcess(name)
	if proc == nil {
		return nil
	}
	return NewErr(runtime.Caller(0)).If(proc.StartIfNotRunning())
}

// 检查受管理的进程，如果有进程没有运行，则启动
func (m *ProcessManager) CheckAndStart() error {
	for _, proc := range m.processes {
		if err := proc.StartIfNotRunning(); err != nil {
			return NewErr(runtime.Caller(0)).Err(err)
		}
	}
	return nil
}
